home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Resources / General / ProNET / src / drivers / mfc-parallel.s < prev    next >
Text File  |  1996-11-30  |  19KB  |  721 lines

  1. *
  2. * mfc-parallel (ProNET driver)
  3. *
  4.  
  5. ******* pronet-driver/--Overview-- ******************************************
  6. *
  7. * This file covers information on how to write custom ProNET drivers.
  8. * As is usual with my distributions ;-(, the API has changed again, but if
  9. * there was really a single custom driver out, it can be changed really easy.
  10. *
  11. * A ProNET driver is an ordinary executable residing in the DEVS:ProNET/
  12. * directory.  This executable will be loaded for every ProNET Unit requiring
  13. * it; it doesn't have to be reentrant.  The code is entered at the very
  14. * first position, which must contain the Init routine.
  15. *
  16. * >> CHANGES FROM V2 DRIVERS <<
  17. *
  18. * New in V3: Exit-Routine, Init-Flags = 1
  19. * New in v37: ReadFlush-Routine, Init-Flags (now called Version) = 2,
  20. *    Write only one chunk, Write timeout support (three return codes now).
  21. *
  22. *****************************************************************************
  23. *
  24. *
  25.  
  26. ;**** The MFCDevKit is not very extensive in explaining how the PIA
  27. ;**** chips work, so I had to search for the stuff myself. Motorola's
  28. ;**** Internet site doesn't know any of their old chips.
  29. ;**** The following text was found in the Internet in an article about
  30. ;**** the Dragon/Tandy hardware. I found `m6821.html' via Altavista and
  31. ;**** the keywords 'mc 6821 pia' or similar.
  32. ;
  33. ; The Dragon and Tandy microcomputers have two Motorola 6821 peripheral
  34. ; interface adapters (PIA) mapped into the address space between $FF00 and
  35. ; $FF3F. The first of these, PIA-0, is located $FF00-$FF03, and the second,
  36. ; PIA-1, is located $FF20-$FF23. The Dragon 64 also has a third PIA at
  37. ; $FF04-$FF07 but this is not discussed here.
  38. ;
  39. ; Each PIA contains two 8-bit I/O ports, port A and port B, where each port
  40. ; and each of the 16 I/O pins are independently programmable as either input
  41. ; or output pins. Two control/interrupt lines are also associated with each
  42. ; port, allowing one extra input/output pin and one input-only pin per port.
  43. ; These pins can trigger an interrupt upon 0->1 or 1->0 transitions, or
  44. ; 'follow' outputs, and are therefore slightly more sophisticated than simple
  45. ; buffers, but can nevertheless be used simply as additional I/O.
  46. ;
  47. ; Each port is accessed and controlled through 3 registers. These are the
  48. ; peripheral data register (PDR), the data direction register (DDR) and the
  49. ; control register (CR). For PIA-0 port A the control register is mapped into
  50. ; the CPU address space at $FF01. However, only two memory addresses are used
  51. ; for each port and therefore both the PDR and DDR cannot be made available
  52. ; simultaneously. Instead bit 2 of the control register must be set or cleared
  53. ; to select whether it is the PDR or DDR which is visible at $FF00. This
  54. ; applies similarly to port B on PIA-0, and both ports of PIA-1.
  55. ;
  56. ; In normal operation the PDR is left visible for each port, with the DDR
  57. ; only made visible when necessary during configuration or reconfiguration.
  58. ;
  59. ; The format of the port registers is as follows:
  60. ;
  61. ;  PDR - 8 bits of data as currently being input/output on the device pins.
  62. ;  DDR - 8 bits, each indicating whether the corresponding PDR bits are for
  63. ;        input (0) or output (1).
  64. ;  CR  - bit 7: control line 1 interrupt status (0 = idle, 1 = request)   RO
  65. ;        bit 6: control line 2 interrupt status (0 = idle, 1 = request)   RO
  66. ;        bit 5: control line 2 direction (0 = input, 1 = output)          RW
  67. ;        bit 4: control line 2 mode (0 = 1->0, 1 = 0->1 or 'follow')      RW
  68. ;        bit 3: control line 2 enable (0 = disable, 1 = enable)           RW
  69. ;        bit 2: PDR/DDR select (0 = DDR, 1 = PDR)                         RW
  70. ;        bit 1: control line 1 mode (0 = 1->0, 1 = 0->1)                  RW
  71. ;        bit 0: control line 1 enable (0 = disable, 1 = enable)           RW
  72. ;
  73. ;                                                          RO = Read only
  74. ;                                                          RW = Read/write
  75. *
  76. * On the Amiga, all PIA registers are ZERO by default (after power-on).
  77. *
  78.  
  79. ; Format of one packet is:
  80. ; 2bytes LENGTH of data including next two words in WORDS-1 !!!!!
  81. ; 2bytes Destination port
  82. ; 2bytes Source port
  83. ; xbytes DATA
  84.  
  85. * I know this is HW banging, but at the moment I don't know how to do
  86. * it in a different way.
  87.  
  88. DISABLEINTS    macro
  89.         move.w    #$4000,$dff09a
  90.         endm
  91. ENABLEINTS    macro
  92.         move.w    #$c000,$dff09a
  93.         endm
  94.  
  95.         include    "A:OSmacros.i"
  96.         include    "exec/exec.i"
  97.         include    "hardware/mfcres.i"
  98.         include    "hardware/piabits.i"
  99.         include    "hardware/intbits.i"
  100.         include    "P:include/devices/pronet.i"
  101.         include    "exec_lib.i"
  102.         include    "intuition_lib.i"
  103.         include    "dos_lib.i"
  104.  
  105. ******* pronet-driver/Init **************************************************
  106. *
  107. *   NAME   
  108. *    Init -- Initialize a ProNET driver.
  109. *
  110. *   SYNOPSIS
  111. *    error = Init(drvdata, confstr, ID, version);
  112. *    D0           A0       A1       D0  D1
  113. *
  114. *    STRPTR Init(struct PNDrvData*, STRPTR, ULONG, ULONG);
  115. *
  116. *   FUNCTION
  117. *    This function is called whenever pronet.device launches a new Unit
  118. *    process.
  119. *
  120. *   INPUTS
  121. *    drvdata - pointer to struct PNDrvData which must be filled out by
  122. *        this routine.
  123. *    confstr - pointer to the configuration string following the driver
  124. *        ID.
  125. *    ID - D0 contains the bytes "RST!" (not a pointer!). Check this to
  126. *        prevent unwanted effects when your driver is started by
  127. *        accident.
  128. *    version - This number identifies the version of pronet.device that is
  129. *        calling this driver. 0=V2, 1=V3, 2=v37; 0 and 1
  130. *        should be rejected with error code NULL!.
  131. *
  132. *   RESULT
  133. *    error - NULL if everything went ok, or a pointer to an error string,
  134. *        of which ProNET will make a copy and hand it to the calling
  135. *        application. You could also return one of the magic cookies
  136. *        as defined in devices/pronet.h for standard errors.
  137. *
  138. *   SEE ALSO
  139. *    devices/pronet.h
  140. *
  141. *****************************************************************************
  142. *
  143. *
  144.  
  145. Init        movem.l    d2-d7/a2-a6,-(sp)
  146.         move.l    a0,a4
  147.         move.l    a1,a5
  148.         cmp.l    #"RST!",d0        ;compare ID
  149.         bne    .ende
  150.         cmp.l    #2,d1            ;0 was the error condition
  151.         bne    .ende            ;in ProNET V2/V3
  152.  
  153.         move.l    #PNDRVERR_WRONG_ARGS,RC
  154.         move.l    a5,a0
  155.         bsr    dec2slong
  156.         tst.w    d4
  157.         bmi.s    .ende
  158.         move.w    d1,PORT
  159.         bsr    dec2slong
  160.         tst.w    d4
  161.         bmi.s    .ende
  162.         move.w    d1,MACHINE
  163.         bsr    dec2slong
  164.         tst.w    d4
  165.         bmi.s    .ende
  166.         move.w    d1,PRIORITY
  167.  
  168.         bsr    AllocPPort
  169.         tst.w    d0
  170.         bne.s    .ende
  171.  
  172.         bsr    InitTransfer
  173.  
  174.         move.l    4.w,a6
  175.         move.l    ThisTask(a6),a1
  176.         move.w    PRIORITY(pc),d0
  177.         LIBCALL    SetTaskPri
  178.  
  179.         move.b    INTsigbit(pc),pndd_ReadSignalBit(a4)
  180.         move.l    #ReadQuery,pndd_ReadQuery(a4)
  181.         move.l    #ReadFlush,pndd_ReadFlush(a4)
  182.         move.l    #Read,pndd_Read(a4)
  183.         move.l    #Write,pndd_Write(a4)
  184.         move.l    #Exit,pndd_Exit(a4)
  185.  
  186.         clr.l    RC
  187.  
  188. .ende        movem.l    (sp)+,d2-d7/a2-a6
  189.         move.l    RC(pc),d0
  190.         rts
  191.  
  192. RC        dc.l    0
  193.  
  194.         dc.b    "$VER: mfc-parallel 37.0 (30.11.96)",13,10,0
  195.         even
  196.  
  197. PORT        dc.w    0
  198. MACHINE        dc.w    0
  199. PRIORITY    dc.w    0
  200.  
  201. dec2slong    ; konvertiert Dezimalstring ab (a0) zu Longword in D1 !!
  202.         ; SIGNED!
  203.         moveq    #-1,d4
  204.         moveq    #0,d1
  205.         moveq    #0,d3
  206.         move.b    (a0),d0
  207.         cmp.b    #"-",d0
  208.         bne.s    .loop
  209.         addq.l    #1,a0
  210.         st    d3
  211. .loop        moveq    #0,d0
  212.         move.b    (a0)+,d0
  213.         sub.b    #"0",d0
  214.         cmp.b    #9,d0
  215.         bhi.s    .oki
  216.         clr.l    d4
  217.         move.l    d1,d2
  218.         lsl.l    #3,d1
  219.         add.l    d2,d1
  220.         add.l    d2,d1
  221.         add.l    d0,d1
  222.         bra.s    .loop
  223. .oki        tst.w    d3
  224.         beq.s    .ende
  225.         neg.l    d1
  226. .ende        rts
  227.  
  228. ******* pronet-driver/Exit **************************************************
  229. *
  230. *   NAME   
  231. *    Exit -- Terminate a ProNET driver.
  232. *
  233. *   SYNOPSIS
  234. *    Exit();
  235. *
  236. *    void Exit(void);
  237. *
  238. *   FUNCTION
  239. *    This function is called whenever pronet.device launches a new Unit
  240. *    process. You must free all resources you allocated previously and
  241. *    return after that.
  242. *
  243. *****************************************************************************
  244. *
  245. *
  246.  
  247. Exit        movem.l    d2-d7/a2-a6,-(sp)
  248.         bsr    ExitTransfer
  249.         bsr    FreePPort
  250.         movem.l    (sp)+,d2-d7/a2-a6
  251.         rts
  252.  
  253. ******* pronet-driver/ReadQuery *********************************************
  254. *
  255. *   NAME   
  256. *    ReadQuery -- find out about an incoming packet.
  257. *
  258. *   SYNOPSIS
  259. *    length, destport, srcport = ReadQuery();
  260. *    D0      D1        D2
  261. *
  262. *    UWORD, UWORD, UWORD = ReadQuery(void);
  263. *
  264. *   FUNCTION
  265. *    This function is called whenever the Unit's task was woken up by
  266. *    the signal bit you provided in drvdata->ReadSignalBit in the Init
  267. *    routine. The signal bit can either be the signal bit of an
  268. *    IORequest reply port or one triggered from an interrupt or
  269. *    process set up by you.
  270. *
  271. *    This function call is used to find out some basic info
  272. *    about the incoming packet before reading the actual data.
  273. *
  274. *   RESULT
  275. *    length - number of bytes of the actual packet data (see NOTES)
  276. *    destport - destination ProNET Port on this machine
  277. *    srcport - source Port on the remote machine
  278. *
  279. *   NOTES
  280. *    If you find out that the ReadSignalBit was triggered by mistake,
  281. *    you can return 0 in the length word, in which case ProNET will go
  282. *    to sleep again. Otherwise it is *guaranteed* that either ReadFlush
  283. *    or Read will be called lateron, no other driver routines will be
  284. *    called in between.
  285. *
  286. *****************************************************************************
  287. *
  288. *
  289.  
  290. ReadQuery    movem.l    d3-d7/a2-a6,-(sp)
  291.  
  292.         move.l    PIAaddr(pc),a3
  293.         btst    #PIAPAB_BUSY,PIA_PRA(a3)
  294.         bne.s    .error        ; check if packet is pending
  295.  
  296.         bclr    #PIACRB_DDR,PIA_CRA(a3)
  297.         bset    #PIAPAB_PAPEROUT,PIA_PRA(a3) ;set POUT(ack) line to output
  298.         bset    #PIACRB_DDR,PIA_CRA(a3)
  299.  
  300.         lea    buffer-2(pc),a4    ; first word is `empty'
  301.         moveq    #3,d4        ; (due to handshake init)
  302.         bsr    ReceiveData
  303.         movem.w    buffer(pc),d0-d2
  304.         subq.w    #2-1,d0
  305.         add.w    d0,d0
  306.         movem.l    (sp)+,d3-d7/a2-a6
  307.         rts
  308. .error        moveq    #0,d0
  309.         movem.l    (sp)+,d3-d7/a2-a6
  310.         rts
  311.  
  312. ******* pronet-driver/ReadFlush *********************************************
  313. *
  314. *   NAME   
  315. *    ReadFlush -- Forget the incoming packet.
  316. *
  317. *   SYNOPSIS
  318. *    ReadFlush();
  319. *
  320. *    void ReadFlush(void);
  321. *
  322. *   FUNCTION
  323. *    This function will only be called if a previous ReadQuery succeeded.
  324. *    ProNET wants us to forget the complete packet.
  325. *
  326. *****************************************************************************
  327. *
  328. *
  329.  
  330. ReadFlush    movem.l    d2-d7/a2-a6,-(sp)
  331.         move.w    buffer(pc),d4
  332.         subq.w    #2,d4
  333.         bsr    FlushData
  334.         bra.s    read_entry
  335.  
  336. ******* pronet-driver/Read **************************************************
  337. *
  338. *   NAME   
  339. *    Read -- read the incoming packet data to a specified memory location.
  340. *
  341. *   SYNOPSIS
  342. *    Read(memptr);
  343. *         A0
  344. *
  345. *    void Read(APTR);
  346. *
  347. *   FUNCTION
  348. *    This function will only be called if a previous ReadQuery succeeded.
  349. *    Here we will copy the packet's data to the specified memory location.
  350. *
  351. *   INPUTS
  352. *    memptr - memory location to which we shall copy
  353. *
  354. *****************************************************************************
  355. *
  356. *
  357.  
  358. Read        movem.l    d2-d7/a2-a6,-(sp)
  359.         move.l    a0,a4
  360.         move.w    buffer(pc),d4
  361.         subq.w    #2,d4
  362.         bsr    ReceiveData
  363.  
  364. read_entry    move.l    PIAaddr(pc),a3
  365.         bclr    #PIACRB_DDR,PIA_CRA(a3)
  366.         bclr    #PIAPAB_PAPEROUT,PIA_PRA(a3) ;set POUT(ack) line to input
  367.         bset    #PIACRB_DDR,PIA_CRA(a3)
  368.  
  369.         movem.l    (sp)+,d2-d7/a2-a6
  370.         rts
  371.  
  372.  
  373. ******* pronet-driver/Write *************************************************
  374. *
  375. *   NAME   
  376. *    Write -- Send a data packet to the remote machine.
  377. *
  378. *   SYNOPSIS
  379. *    error = Write(dataptr, length, destport, srcport);
  380. *    D0            A0       D0      D1        D2
  381. *
  382. *    ULONG Write(APTR, ULONG, UWORD, UWORD);
  383. *
  384. *   FUNCTION
  385. *    I guess this will always be the most complex function of a driver.
  386. *    Try to get a connection to the remote machine and send the packet
  387. *    as requested. A kind of flow control, like a timeout feature,
  388. *    should be implemented.
  389. *
  390. *   INPUTS
  391. *    dataptr - pointer to the data to be transmitted
  392. *    length - length of data to be transmitted. The length is limited
  393. *        to 16384 bytes and it is even.
  394. *    destport - destination Port on the remote machine
  395. *    srcport - source Port on this machine
  396. *
  397. *   RESULT
  398. *    error - 0  if packet could be sent without trouble.
  399. *        -1 if the line is currently busy -- pronet.device will then
  400. *           try again later.
  401. *        1  if the remote machine does not respond. The application
  402. *           will be notified in this case, CMD_WRITE returns with
  403. *           an error (PNDERR_DESTINATION_GONE).
  404. *
  405. *   NOTES
  406. *    Your driver is responsible for correct transmission of the data,
  407. *    by using checksums or similar mechanisms.
  408. *
  409. *****************************************************************************
  410. *
  411. *
  412.  
  413. Write        movem.l    d2-d7/a2-a6,-(sp)
  414.  
  415.         lea    buffer(pc),a5
  416.         move.l    a0,6(a5)
  417.         move.l    d0,10(a5)
  418.  
  419.         move.w    d1,(a5)
  420.         move.w    d2,2(a5)
  421.  
  422.         move.w    d0,d4
  423.         lsr.w    #1,d4
  424.         addq.w    #2-1,d4
  425.         bsr    AcquireLine
  426.         tst.w    d0            ;Line is busy now! Try later
  427.         bne.s    .ende
  428.  
  429.         move.l    a5,a4
  430.         moveq    #1,d4
  431.         moveq    #0,d6
  432.         bsr    SendData
  433.  
  434.         move.l    6(a5),a4    ; The last word gets sent separately.
  435.         move.l    10(a5),d4
  436.         lsr.w    #1,d4
  437.         subq.w    #2,d4
  438.         bmi.s    .0
  439.         bsr    SendData
  440.  
  441. .0        DISABLEINTS        * We don't take too long here
  442.         moveq    #0,d4        * in case the other machine wants
  443.         bsr    SendData    * to send something...
  444.  
  445.         clr.w    sending
  446.         bsr    InitParallel
  447.         ENABLEINTS
  448.  
  449.         moveq    #0,d0
  450. .ende        movem.l    (sp)+,d2-d7/a2-a6
  451.         rts
  452.  
  453.         dc.w    0
  454. buffer        dc.w    0,0,0
  455.         dc.l    0,0
  456.  
  457.  
  458. ; -- Allocate the specified MFC port.
  459. AllocPPort    move.l    4.w,a6
  460.         lea    mfcname(pc),a1
  461.         LIBCALL    OpenResource
  462.         move.l    #err1,RC
  463.         move.l    d0,mfcbase
  464.         beq.s    APP_nores
  465.  
  466.         move.l    d0,a6
  467.         moveq    #0,d0
  468.         move.w    PORT(pc),d0
  469.         lea    drivername(pc),a0
  470.         LIBCALL    AllocPort
  471.         move.l    #err2,RC
  472.         move.l    d0,portnode
  473.         beq.s    APP_noport
  474.  
  475.         move.l    d0,a0
  476.         move.l    port_ChipNode(a0),a0
  477.         move.l    chip_Product(a0),d0
  478.         move.l    #err3,RC
  479.         cmp.l    #CHIP_PIA,d0
  480.         bne.s    APP_wrongcard
  481.         move.l    chip_Address(a0),PIAaddr
  482.  
  483.         moveq    #0,d0
  484.         rts
  485.  
  486. FreePPort
  487. APP_wrongcard    move.l    mfcbase(pc),a6
  488.         move.l    portnode(pc),a0
  489.         LIBCALL    FreePort
  490. APP_noport
  491. APP_nores    moveq    #-1,d0
  492.         rts
  493.  
  494. mfcname        dc.b    "mfc.resource",0
  495. drivername    dc.b    "ProNET MultiFaceCard3 Driver",0
  496. err1        dc.b    "Can't find mfc.resource.",0
  497. err2        dc.b    "Can't open specified MFC parallel port.",0
  498. err3        dc.b    "The specified port is no MC6821 PIA.",0
  499.         even
  500. mfcbase        dc.l    0
  501. portnode    dc.l    0
  502. PIAaddr        dc.l    0
  503.  
  504. ; -- Init Transfer routines
  505. InitTransfer    move.l    4.w,a6
  506.         move.l    ThisTask(a6),INTsigtask
  507.  
  508.         moveq    #-1,d0
  509.         LIBCALL    AllocSignal
  510.         move.b    d0,INTsigbit
  511.  
  512.         move.l    4.w,a6
  513.         moveq    #INTB_PORTS,d0
  514.         lea    INTstruct(pc),a1
  515.         LIBCALL    AddIntServer
  516.  
  517.         bsr    InitParallel
  518.         rts
  519.  
  520. ExitTransfer
  521.         bsr    ExitParallel
  522.  
  523.         move.l    4.w,a6
  524.         moveq    #INTB_PORTS,d0
  525.         lea    INTstruct(pc),a1
  526.         LIBCALL    RemIntServer
  527.  
  528.         move.b    INTsigbit(pc),d0
  529.         LIBCALL    FreeSignal
  530.         rts
  531.  
  532. INTsigtask    dc.l    0
  533. INTsigbit    dc.w    0
  534.  
  535. INTstruct    dc.l    0,0
  536.         dc.b    2,0
  537.         dc.l    drivername
  538.         dc.l    0,INTcode
  539. INTcode        moveq    #0,d0
  540.         move.l    PIAaddr(pc),a0
  541.         btst    #PIACRB_IRQ1,PIA_CRB(a0)    ;PIA IRQ1?
  542.         beq.s    .no
  543.         move.b    PIA_PRB(a0),d1            ;Clear IRQ bit
  544.         tst.w    sending
  545.         bne.s    .no
  546.         btst    #PIAPAB_BUSY,PIA_PRA(a0)    ;check if we
  547.         bne.s    .no                ;were really called
  548.         move.l    4.w,a6                ;or other machine
  549.         move.l    INTsigtask(pc),a1        ;was switched on!
  550.         move.b    INTsigbit(pc),d1
  551.         moveq    #0,d0
  552.         bset    d1,d0
  553.         LIBCALL    Signal
  554.         moveq    #1,d0
  555. .no        rts
  556.  
  557. ;:---------------------------------------------------------------------------
  558. ;:-- InitParallel
  559. InitParallel
  560.         move.l    PIAaddr(pc),a0
  561.  
  562.         move.b    #%00000100,PIA_CRA(a0)
  563.         move.b    #%00000111,PIA_PRA(a0)    ;control lines to 1 (when we set them to output)
  564.         move.b    #%00000000,PIA_CRA(a0)
  565.         move.b    #%00000000,PIA_PRA(a0)    ;control lines -> input
  566.         move.b    #%00000100,PIA_CRA(a0)    ;PR-Register is default
  567.  
  568.         move.b    #%00000000,PIA_CRB(a0)
  569.         sf    PIA_PRB(a0)    ;data lines input
  570.         move.b    #%00000101,PIA_CRB(a0)    ;CB1-interrupt enablen
  571.         rts
  572.  
  573. ExitParallel
  574.         move.l    PIAaddr(pc),a0
  575.         move.b    #%00000100,PIA_CRB(a0)    ;C1-interrupt disablen
  576.         rts
  577.  
  578.  
  579. ;:---------------------------------------------------------------------------
  580. ;:-- AcquireLine
  581. ;:-- d4 Number of words-1 that will be sent !
  582. ;:-- !!!!!! RETURNS d0=0  if no error
  583. ;:--                d0=-1 if line was busy
  584. AcquireLine
  585.         move.l    PIAaddr(pc),a3
  586.  
  587.         DISABLEINTS
  588.         btst    #PIAPAB_BUSY,PIA_PRA(a3)
  589.         bne.s    .free
  590.         ENABLEINTS
  591.         moveq    #-1,d0
  592.         rts
  593.  
  594. .free        st    sending
  595.  
  596.         * Set BUSY line
  597.         bclr    #PIACRB_DDR,PIA_CRA(a3)
  598.         bset    #PIAPAB_BUSY,PIA_PRA(a3) ;BUSY = output
  599.         bset    #PIACRB_DDR,PIA_CRA(a3)
  600.         bclr    #PIAPAB_BUSY,PIA_PRA(a3) ;BUSY = 0
  601.  
  602.         * Toggle SELECT line to cause interrupt on server
  603.         bclr    #PIACRB_DDR,PIA_CRA(a3)
  604.         bset    #PIAPAB_SELECTED,PIA_PRA(a3)    ;output
  605.         bset    #PIACRB_DDR,PIA_CRA(a3)
  606.         bclr    #PIAPAB_SELECTED,PIA_PRA(a3)    ;toggle
  607.         bset    #PIAPAB_SELECTED,PIA_PRA(a3)    ;
  608.         bclr    #PIACRB_DDR,PIA_CRA(a3)
  609.         bclr    #PIAPAB_SELECTED,PIA_PRA(a3)    ;input
  610.         bset    #PIACRB_DDR,PIA_CRA(a3)
  611.  
  612.         ENABLEINTS
  613.  
  614.         tst.w    firstpacketflag    ; no timeout for the first packet!
  615.         beq.s    .acknotimeout
  616.         tst.w    MACHINE        ; no timeout for machine 1!
  617.         bne.s    .acknotimeout
  618.  
  619.         move.l    #100000,d0
  620. .ack0        btst    #PIAPAB_PAPEROUT,PIA_PRA(a3) ; wait for it to respond...
  621.         beq.s    .ack0ok
  622.         subq.l    #1,d0
  623.         bne.s    .ack0
  624.  
  625.         bset    #PIAPAB_BUSY,PIA_PRA(a3)
  626.         bsr    InitParallel    ;Timeout! Reset all lines!
  627.         bsr    INTcode
  628.         moveq    #-1,d0
  629.         rts
  630.  
  631. .acknotimeout    btst    #PIAPAB_PAPEROUT,PIA_PRA(a3)
  632.         bne.s    .acknotimeout
  633.  
  634. .ack0ok        st    firstpacketflag
  635.         bset    #PIAPAB_BUSY,PIA_PRA(a3) ; and initialize handshake sequence
  636. .ack1        btst    #PIAPAB_PAPEROUT,PIA_PRA(a3)
  637.         beq.s    .ack1
  638.  
  639.         bclr    #PIACRB_DDR,PIA_CRB(a3)
  640.         st    PIA_PRB(a3)    ; DATA = output
  641.         bset    #PIACRB_DDR,PIA_CRB(a3)
  642.  
  643.         ror.w    #8,d4        ; and hand the length word over
  644.         move.b    d4,PIA_PRB(a3)    ; to the remote machine
  645.         bclr    #PIAPAB_BUSY,PIA_PRA(a3)
  646.         ror.w    #8,d4
  647. .ack2        btst    #PIAPAB_PAPEROUT,PIA_PRA(a3)
  648.         bne.s    .ack2
  649.         move.b    d4,PIA_PRB(a3)
  650.         bset    #PIAPAB_BUSY,PIA_PRA(a3)
  651. .ack3        btst    #PIAPAB_PAPEROUT,PIA_PRA(a3)
  652.         beq.s    .ack3
  653.         moveq    #0,d0
  654.         rts
  655.  
  656. firstpacketflag    dc.w    0
  657. sending        dc.w    0
  658.  
  659. ;:---------------------------------------------------------------------------
  660. ;:-- SendData
  661. ;:-- a4 *data
  662. ;:-- d4 datalength in words-1
  663. SendData
  664.         move.l    PIAaddr(pc),a2
  665.         lea    PIA_PRB(a2),a0
  666.         lea    PIA_PRA(a2),a2
  667.  
  668.         move.b    #%11111110,d0    ; clear BUSY
  669.         move.b    #%00000001,d1    ; set BUSY
  670.  
  671. .loop        move.b    (a4)+,(a0)    ; fully handshaked data txfer
  672.         and.b    d0,(a2)
  673. .ack0        btst    #PIAPAB_PAPEROUT,(a2)
  674.         bne.s    .ack0
  675.         move.b    (a4)+,(a0)
  676.         or.b    d1,(a2)
  677. .ack1        btst    #PIAPAB_PAPEROUT,(a2)
  678.         beq.s    .ack1
  679.         dbra    d4,.loop
  680.         rts
  681.  
  682. ;:---------------------------------------------------------------------------
  683. ;:-- ReceiveData
  684. ;:-- a4 *datadest
  685. ;:-- d4 datalength in words-1
  686. ReceiveData
  687.         move.l    PIAaddr(pc),a2
  688.         lea    PIA_PRB(a2),a0
  689.         lea    PIA_PRA(a2),a2
  690.  
  691.         move.b    #%11111101,d0    ; clear POUT
  692.         move.b    #%00000010,d1    ; set POUT
  693.  
  694. .loop        btst    #PIAPAB_BUSY,(a2)
  695.         bne.s    .loop
  696.         move.b    (a0),(a4)+
  697.         and.b    d0,(a2)
  698. .ack0        btst    #PIAPAB_BUSY,(a2)
  699.         beq.s    .ack0
  700.         move.b    (a0),(a4)+
  701.         or.b    d1,(a2)
  702.         dbra    d4,.loop
  703.         rts
  704.  
  705. FlushData
  706.         move.l    PIAaddr(pc),a2
  707.         lea    PIA_PRB(a2),a0
  708.         lea    PIA_PRA(a2),a2
  709.  
  710.         move.b    #%11111101,d0    ; clear POUT
  711.         move.b    #%00000010,d1    ; set POUT
  712.  
  713. .loop        btst    #PIAPAB_BUSY,(a2)
  714.         bne.s    .loop
  715.         and.b    d0,(a2)
  716. .ack0        btst    #PIAPAB_BUSY,(a2)
  717.         beq.s    .ack0
  718.         or.b    d1,(a2)
  719.         dbra    d4,.loop
  720.         rts
  721.